package com.smsc.headend.task.engine.executor.impl.firmware;

import cn.hutool.core.convert.Convert;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.entity.DeviceOperation;
import com.smsc.headend.module.data.dmo.DeviceSAPandKeys;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.DictionaryType;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskExecutorException;
import com.smsc.headend.task.engine.executor.TaskExecutor;
import com.smsc.headend.task.engine.facade.DataItemFacade;
import com.smsc.headend.task.engine.handler.impl.firmware.GetFirmwareVersionHandler;
import com.smsc.headend.module.task.dto.AtomicTaskState;
import com.smsc.headend.task.engine.service.ConnectorService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.task.TaskPacketService;
import com.smsc.headend.task.engine.service.task.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 获取DCU或Meter固件版本
 *
 * @author qinbin
 * @date 2021/04/28
 */
@Slf4j
public class GetFirmwareVersionExecutor implements TaskExecutor {


    @Autowired
    TaskPacketService packetService;

    @Autowired
    ConnectorService connectorService;

    @Autowired
    FeignAssetManagementService assetManagementRemoteService;

    @Autowired
    AssetService assetService;

    @Autowired
    DataItemFacade dataItemFacade;

    @Autowired
    TaskService taskService;

    @Autowired
    TaskDAO taskDAO;

    @Override
    public AtomicTaskState execute(Task task, AtomicTask atomicTask) throws UDISTaskExecutorException {

        DeviceOperation dictionary = assetService.getDictionary(atomicTask.getOperationId(), DictionaryType.Operation.getType());
        Meter meter = getMeter(task, assetService);
        MeterConfigDMO meterConfigDMO = task.getMeterId() == null ? null : assetService.getMeterConfigById(task.getMeterId());
        ComEntity terminal = assetService.getComById(task.getComId());
        ComConfigDMO comConfigDMO = assetService.getComConfigById(task.getComId());

        List<DataItemDTO> dataItemCosemList = dataItemFacade.getDataItemsByOperation(meter, terminal, dictionary, getParameterMap(task, atomicTask), comConfigDMO.getModelId());
        if (CollectionUtils.isEmpty(dataItemCosemList)) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATAITEM_NOT_EXISTS.toString());
        }

        Boolean isReadFromTerminal = isReadFromTerminal(task);
        DataItemDTO dataItemDto = dataItemCosemList.get(0);
        DeviceSAPandKeys deviceKeys = meter != null ? assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDto.getRoleId()) :
                assetManagementRemoteService.getTerminalCommunicationKey(terminal.getComId(), dataItemDto.getRoleId());

        Long fwTypeId = Convert.toLong(this.getParameterMap(task, atomicTask).get("fwTypeId"));
        //SMOD模块读取加入表信息
        byte[] packets;
        if (null != fwTypeId && fwTypeId == 10L) {
            packets = packetService.buildReadOneAttributePacketWithMfgSn(dataItemCosemList.get(0), meter, meterConfigDMO, deviceKeys);
            //read from dcu need to set Connector Task meter Id to Null
            task.setMeterId(null);
        } else {
            packets = packetService.buildReadOneAttributePacket(dataItemCosemList.get(0), isReadFromTerminal ? comConfigDMO : meterConfigDMO, deviceKeys);
        }

        if (packets == null) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.BUILD_REQUEST_FAIL.toString());
        }
        log.info("GetFirmwareVersionExecutor send packets: " + ByteUtils.byteToHexString(packets));
        connectorService.sendPacket(task, atomicTask, dataItemCosemList.get(0).getRoleId(), task.getIsODR(), packets);
        //set meterId back
        if (null != meter) {
            task.setMeterId(meter.getMeterId());

        }
        return createAtomicState(GetFirmwareVersionHandler.class);
    }

    @Override
    public Boolean handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        String fwTypeId = (String) this.getParameterMap(task, atomicTask).get("fwTypeId");
        if (atomicTask.getGroupId() == OperationGroup.GetFirmwareVersion.getId().intValue()) {
            if (task.getIsODR()) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), fwTypeId, String.format("[%s]", message), 3600L, false);
            }
        }
        return true;
    }


    private Boolean isReadFromTerminal(Task task) {
        if (task.getMeterId() == null) {
            return true;
        }
        return false;
    }


}

